#ifndef _INCLUDE_ONET_C_UDP_PORT
#define _INCLUDE_ONET_C_UDP_PORT_

/*!
    Copright: Kai "DrHalan" Mast - www.freakybytes.org

    This file is part of OpenNetwork. See OpenNetwork.h for license information.
*/


#include "include/OpenNetwork/INetworkPort.h"

#include "SUDPPeer.h"

#ifdef __WINDOWS__
#include <winsock2.h>
#elif defined(__unix__)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#else
#error "What's your operating system?"
#endif

#include <fcntl.h>

#include "common.h"

namespace onet
{

    class CUDPPort : public INetworkPort
    {
    public:
        CUDPPort(INetworkCallback* callback_, u16 maxConnections_, u16 port_, bool listen_, bool IPv6_);

        ~CUDPPort();

        //! Initialization function
        virtual bool init(void);

        //! Connect to an address
        //! Returns false if already connected
        virtual bool connect(const SNetworkAddress& address);

        //! The disconnect pendant
        //! Returns false if the peerID is invalid
        virtual bool disconnect(const PeerID id);

        //! Disconnects all peers
        //! Returns number of peers disconnected
        virtual u16 disconnectAll(void);

        //! Get the latency of a peer
        virtual s32 getLatency(const PeerID id);

        //! Gets the address (IP/Port) of a peer
        virtual SNetworkAddress getAddress(const PeerID id);

        //! Looks up if a certain address is connected
        virtual bool isConnected(const SNetworkAddress& a);

        //! Gets the Id of a certain address
        virtual PeerID getPeer(const SNetworkAddress& a);

        //! Sends and receives data
        virtual void work(void);

        //! Get the protocol used
        virtual EPortType getType(void) const;

        //! Send data to peer - Reliable or not
        virtual bool send(const PeerID id, const u8 type, const u32 length, const c8* data, const bool reliable);

        //! Send data to address
        virtual bool sendRaw(const SNetworkAddress& address, const u16 length, const c8* data);

        //! Query certain features
        virtual bool hasFeature(EFeatureType type) const;

        //! Returns number of peers connected
        virtual u16 getPeerCount();

    private:
        //! Remove a peer (!= disconnect)
        bool removePeer(PeerID id);

        //! Adds a peer (!= connect)
        PeerID addPeer(SNetworkAddress address);

        //! Processes out messages
        void processSending();

        //! Processes in messages
        void processReceiving();

        //! Do ping/pong
        void doPingPong(PeerID id);

        //! Do reliable stuff
        void doReliable(PeerID id);

        //! Pointer to the peer array
        PointerArray<SUDPPeer> peers;

        //! Vector of packages
        std::vector<SUDPMessage> messages;

        //! Socket used to send and receive data
        s32 socketfd;

        //! Buffer for receiving messages
        c8 buffer[1024];

        //! Internal send fucntion you can set a reliable id here
        bool internal_send(const PeerID id, const u8 type, const u16 length, const c8* data, const bool reliable, s32 reliableId);
    };

} //!end namespace onet

#endif
